About Philadelphia

Philadelphia, Pennsylvania’s largest city, is notable for its rich history, on display at the Liberty Bell, Independence Hall (where the Declaration of Independence and Constitution were signed) and other American Revolutionary sites. Also iconic are the steps of the Philadelphia Museum of Art, immortalized by Sylvester Stallone’s triumphant run in the film “Rocky.”

Data was provided by https://www.opendataphilly.org/

Crime Incidents

Crime incidents from the Philadelphia Police Department. Part I crimes include violent offenses such as aggravated assault, rape, arson, among others. Part II crimes include simple assault, prostitution, gambling, fraud, and other non-violent offenses.

This dataset previously had separate endpoints for various years and types of incidents. These have since been consolidated into a single dataset.

Loading and taking a look into the dataset

#install.packages("lubridate")
#install.packages("virid")
#install.packages("plotly")
#install.packages("tm")
#install.packages("wordcloud")
#install.packages("leaflet")
#install.packages("xts")
#install.packages("highcharter")
#install.packages("forecast")
library(data.table)
library(forecast)
library(knitr)
library(tseries)
library(dplyr)
library(ggplot2)
library(lubridate)
library(tidyr)
library(viridis)
library(plotly)
library(tm)
library(wordcloud)
library(RColorBrewer)
library(leaflet)
library(xts)
library(highcharter)

Data size and structure.

crime_data <- fread("philly_crime.csv", showProgress = FALSE)
dim(crime_data)
[1] 2692698      16
str(crime_data)
Classes ‘data.table’ and 'data.frame':  2692698 obs. of  16 variables:
 $ the_geom            : chr  "0101000020E610000091CDD92B01CA52C0952201BCE8FA4340" "0101000020E61000001007E842D5C952C02EC046ABBDF94340" "0101000020E610000081BA799166CE52C0B30631C8C4F84340" "0101000020E6100000E140CC4E94CB52C08C7BFB8CEEF74340" ...
 $ dispatch_time       : chr  "01:52:00" "01:52:00" "01:36:00" "01:26:00" ...
 $ the_geom_webmercator: chr  "0101000020110F000027DA0ADC46EA5FC1E0FB0B15418A5241" "0101000020110F000097C72A46FCE95FC1E10189BAF5885241" "0101000020110F00007DA9A475BEF15FC115D02801E2875241" "0101000020110F00009316A2A0F3EC5FC1A5E792B2F4865241" ...
 $ objectid            : int  40069885 40084126 40069893 40086032 40077029 40061230 40065620 40062106 40086022 40081265 ...
 $ dc_dist             : int  6 6 12 17 22 39 12 25 14 25 ...
 $ psa                 : chr  "1" "2" "4" "3" ...
 $ dispatch_date_time  : chr  "2019-12-11 01:52:00" "2019-12-11 01:52:00" "2019-12-11 01:36:00" "2019-12-11 01:26:00" ...
 $ dispatch_date       : chr  "2019-12-11" "2019-12-11" "2019-12-11" "2019-12-11" ...
 $ cartodb_id          : int  2688326 2676639 2688696 2674928 2649006 2619877 2667540 2632680 2674305 2676701 ...
 $ hour_               : int  1 1 1 1 1 0 0 0 0 0 ...
 $ dc_key              :integer64 201906064387 201906064385 201912105504 201917056325 201922108803 201939105668 201912105489 201925099886 ... 
 $ location_block      : chr  "1000 BLOCK HAMILTON ST" "800 BLOCK MARKET ST" "1100 BLOCK S 53RD ST" "2200 BLOCK OAKFORD ST" ...
 $ ucr_general         : int  400 2600 600 800 1400 2600 1800 800 800 1500 ...
 $ text_general_code   : chr  "Aggravated Assault No Firearm" "All Other Offenses" "Thefts" "Other Assaults" ...
 $ point_x             : num  -75.2 -75.2 -75.2 -75.2 -75.2 ...
 $ point_y             : num  40 40 39.9 39.9 40 ...
 - attr(*, ".internal.selfref")=<externalptr> 
table(is.na(crime_data))

   FALSE     TRUE 
43035999    47169 
  • Over 47k records have missing values.
  • Deleting records having missing values.
crime_data<-na.omit(crime_data)
table(is.na(crime_data))

   FALSE 
42667440 
  • No missing values now

Extract Month and Year from the dispatch_date_time attribute

crime_data$Month_Year <- format(as.POSIXct(strptime(crime_data$dispatch_date_time,"%Y-%m-%d %H:%M:%S",tz="GMT")) ,format = "%Y-%m")
crime <- as.data.frame(crime_data)
crime$Day <- day(crime$dispatch_date_time)
crime$Year <- factor(year(crime$dispatch_date_time), levels=2006:2019)
crime$Month <- factor(month(crime$dispatch_date_time), levels=1:12)
crime$dispatch_date <- as.Date(crime$dispatch_date)

Time Series plot of Philadelphia Crimes

Since the data is in a series of particular time periods or intervals, we are plotting time series to look at trends over years

by_date <- crime %>% group_by(dispatch_date) %>% summarise(Total = n())
tseries <- xts(by_date$Total, order.by=as.POSIXct(by_date$dispatch_date))
hchart(tseries, name = "Crimes") %>% 
  hc_add_theme(hc_theme_darkunica()) %>%
  hc_credits(enabled = TRUE, text = "Data Source: https://www.opendataphilly.org/ ", style = list(fontSize = "12px")) %>%
  hc_title(text = "Time Series plot of Philadelphia Crimes") %>%
  hc_legend(enabled = TRUE)

Location with Most Crimes - Top 20

by_location <- crime %>% group_by(location_block) %>% 
  summarise(Total = n()) %>% arrange(desc(Total))
hchart(by_location[1:20,], "column", hcaes(x = location_block, y = Total, color = Total)) %>%
  hc_colorAxis(stops = color_stops(n = 10, colors = c("#440321", "#21908C", "#FDE725"))) %>%
  hc_add_theme(hc_theme_darkunica()) %>%
  hc_title(text = "Locations with most Crimes - Top 20") %>%
  hc_credits(enabled = TRUE, text = "Data Source: https://www.opendataphilly.org/", style = list(fontSize = "15px")) %>%
  hc_legend(enabled = FALSE)

We can observe that 5200 BLOCK Frankford Ave has highest number of crimes recorded.

Month comparison for each year(2006 - 2019)

monthplot <- ggplot(crime, aes(Year)) + 
    geom_bar(fill="#FF8685") +
    ggtitle("Month comparison for each year(2006 - 2019)") +
    facet_wrap(~Month) +
    theme(axis.text.x = element_text(angle=120))
gg2 <- ggplotly(monthplot)
gg2

Crimes by Hour, Day, Month and Year

by_hour <- crime %>% 
  group_by(hour_) %>% 
  dplyr::summarise(Total = n())
by_hour
ggplot(by_hour, aes(hour_, Total, color = hour_)) + 
  geom_line() + 
  ggtitle("Crimes By Hour") + 
  xlab("Hour of the Day") + 
  ylab("Total Crimes") 


by_day <- crime %>% 
  group_by(Day) %>% 
  dplyr::summarise(Total = n())
by_day

ggplot(by_day, aes(Day, Total, color = Day)) + 
  geom_line() + 
  ggtitle("Crimes By Day") + 
  xlab("Day of the Month") + 
  ylab("Total Crimes") 


by_month <- crime %>% 
  group_by(Month) %>% 
  dplyr::summarise(Total = n())

by_month$Percent <- by_month$Total/dim(crime)[1] * 100
by_month

ggplot(by_month, aes(Month, Total, fill = Month)) + 
  geom_bar(stat = "identity") + 
  ggtitle("Crimes By Month") + 
  xlab("Month") + 
  ylab("Count") + 
  theme(legend.position = "none")


by_year <- crime %>% 
  group_by(Year) %>% 
  dplyr::summarise(Total = n())
by_year$Percent <- by_year$Total/dim(crime)[1] * 100
by_year

ggplot(by_year, aes(Year, Total, fill = Year)) + 
  geom_bar(stat = "identity") +
  ggtitle("Crimes By Year ") + 
  xlab("Year") + ylab("Count") + 
  theme(legend.position = "none")



by_hour_year <- crime %>% 
  group_by(Year,hour_) %>%
  dplyr::summarise(Total = n())

ggplot(by_hour_year, aes(hour_, Total, color = Year)) + 
  geom_line(size = 1) + 
  ggtitle("Crimes By Year and Hour") + 
  xlab("Hour of the Day") + 
  ylab("Total Crimes") 


by_hour_month <- crime %>% 
  group_by(Month,hour_) %>% 
  dplyr::summarise(Total = n())

ggplot(by_hour_month, aes(hour_, Total, color = Month)) + 
  geom_line(size = 1) + 
  ggtitle("Crimes By Month and Hour") + 
  xlab("Hour of the Day") + 
  ylab("Total Crimes") 


by_month_day <- crime %>% 
  group_by(Month, Day) %>% 
  dplyr::summarise(Total = n())

ggplot(by_month_day, aes(Day, Total, color = Month)) + 
  geom_line(size = 2) + 
  ggtitle("Crimes By Month and Day") + 
  xlab("Day") + 
  ylab("Count")



by_month_year <- crime %>% 
  group_by(Year, Month) %>% 
  dplyr::summarise(Total = n())

ggplot(by_month_year, aes(Year, Month, fill = Total)) + 
  geom_tile(color = "white") + 
  ggtitle("Crimes By Year and Month") + 
  xlab("Year") + 
  ylab("Month") 

Crimes by Code, Month and Year

by_code <- crime %>% 
  group_by(text_general_code) %>% 
  dplyr::summarise(Total = n()) %>% 
  arrange(desc(Total))

by_code[1:50,]

ggplot(by_code, aes(reorder(text_general_code, Total), Total)) + 
  geom_bar(stat = "identity") + coord_flip() +  
  scale_y_continuous(breaks = seq(0,450000,50000)) + 
  ggtitle("Crimes By Code") + 
  xlab("Crime Text Code") + 
  ylab("Total Crimes")


by_code_year <- crime %>% group_by(Year, text_general_code) %>% 
  dplyr::summarise(Total = n())

by_code_year[1:10,]

ggplot(by_code_year, aes(reorder(text_general_code, Total), Total, fill = Year)) + 
  geom_bar(stat = "identity") + 
  scale_y_continuous(breaks = seq(0,450000,50000)) + 
  coord_flip() + ggtitle("Crimes By Code and Year") + 
  xlab("Crime Text Code") + 
  ylab("Total Crimes")



by_code_month <- crime %>% 
  group_by(Month, text_general_code) %>% 
  dplyr::summarise(Total = n())
by_code_month[1:10,]
ggplot(by_code_month, aes(reorder(text_general_code, Total), Total, fill = Month)) + 
  geom_bar(stat = "identity") + 
  scale_y_continuous(breaks = seq(0,450000,50000)) + 
  coord_flip() + 
  ggtitle("Crimes By Code and Month") + 
  xlab("Crime Text Code") + 
  ylab("Total Crimes")

Crime Types

by_type <- crime %>% group_by(text_general_code) %>% 
  summarise(Total = n()) %>% arrange(desc(Total))
hchart(by_type, "column", hcaes(text_general_code, y = Total, color = Total)) %>%
  hc_colorAxis(stops = color_stops(n = 10, colors = c("#440154", "#21908C", "#FDE725"))) %>%
  hc_add_theme(hc_theme_darkunica()) %>%
  hc_title(text = "Crime Types") %>%
  hc_credits(enabled = TRUE, text = "Sources: Philadelphia Police Department", style = list(fontSize = "12px")) %>%
  hc_legend(enabled = FALSE)

Some Top Crimes

plotcrime  <- function(varcrime) {
  crimes <- crime[crime$text_general_code == varcrime,] 
  crimes_by_date <- crimes %>% group_by(dispatch_date) %>% dplyr::summarise(Total = n())
  crimes_by_date$dispatch_date <- as.Date(crimes_by_date$dispatch_date)
  tseries <- xts(crimes_by_date$Total, order.by=as.POSIXct(crimes_by_date$dispatch_date))
  hchart(tseries, name = "Crimes") %>% 
    hc_colorAxis(stops = color_stops(n = 10, colors = c("#440154", "#21908C", "#FDE725"))) %>%
    hc_add_theme(hc_theme_darkunica()) %>%
    hc_title(text = varcrime) %>%
    hc_credits(enabled = TRUE, text = "Sources: Philadelphia Police Department", style = list(fontSize = "12px")) %>%
    hc_legend(enabled = FALSE)
}
plotcrime("All Other Offenses")
plotcrime("Other Assaults")
plotcrime("Thefts")
plotcrime("Fraud")
plotcrime("Theft from Vehicle")
plotcrime("Vandalism/Criminal Mischief")
plotcrime("Narcotic / Drug Law Violations")

Crimes by District Police HeadQuarters and Police Service Area

table(crime$dc_dist)

     1      2      3      4      5      6      7      8      9     12     14     15     16     17     18 
 55651 135720 104309  28986  37285 115681  51839  85616 102887 154996 145648 216992  89963  86901 132999 
    19     22     23     24     25     26     35     39     77     92 
172160 157360  27117 197472 177079 102933 158319 121815   5695   1292 
table(crime$psa)

     1      2      3      4      A      B      C      D      E      F      G      H      I      J      K 
584514 649986 525161  81467  44513  37164  34798  51656  52898  48318  47733  50549  45626  50883  51178 
     L      M      N      O      P      Q      R      S      T      U      V      W      X      Y      Z 
 41421  38498  42540  33614  43998  20938  25336  28468   9629  10757   2465   2584   6321   1958   1744 
crime$dc_dist <- factor(crime$dc_dist)

by_dc <- crime %>% group_by(dc_dist) %>% 
  dplyr::summarise(Total = n()) %>% 
  dplyr::arrange(desc(Total))

by_dc_psa <- crime %>% 
  group_by(dc_dist, psa) %>% 
  dplyr::summarise(Total = n())

ggplot(by_dc, aes(reorder(dc_dist, -Total), Total)) + 
  geom_bar(stat = "identity") + 
  ggtitle("Crimes by District Police HeadQuarters") + 
  xlab("Police HQ") + 
  ylab("Total Crimes") 

by_dc_top5 <- by_dc$dc_dist[1:5]
by_top5_dc <- subset(crime, dc_dist %in% by_dc$dc_dist[1:5])
by_top5_dc$dc_dist <- factor(by_top5_dc$dc_dist)

ggplot(by_top5_dc, aes(dc_dist, fill = psa)) + 
  geom_bar(position = "dodge") + 
  ggtitle("Crimes by District Police HeadQuarters - Top 5") + 
  xlab("Police HQ") + 
  ylab("Total Crimes") 


ggplot(by_dc_psa, aes(dc_dist, psa, fill = Total)) + 
  geom_tile(color = "white") + 
  ggtitle("Crimes by District Police HeadQuarters and Police Service Area") + 
  xlab("District Police HeadQuarters") + 
  ylab("Police Service Area") 

Top crime in every District Head Quarters and every Police Service Area

dc_by_crime <- crime  %>% 
  group_by(dc_dist, text_general_code) %>% 
  dplyr::summarise(Total = n()) %>% 
  arrange(desc(Total)) %>% top_n(n = 1)
Selecting by Total
dc_by_crime <- as.data.frame(dc_by_crime)
dc_by_crime$dc_dist <- factor(dc_by_crime$dc_dist)
dc_by_crime$text_general_code <- factor(dc_by_crime$text_general_code)

ggplot(dc_by_crime, aes(dc_dist, Total, fill = text_general_code)) + 
  geom_bar(stat = "identity") + 
  ggtitle("Top Crime by District Police HeadQuarters") + 
  xlab("District Police HeadQuarters") + 
  ylab("Total") 


crime_by_psa <- crime  %>% 
  group_by(psa, text_general_code) %>% 
  dplyr::summarise(Total = n()) %>% 
  arrange(desc(Total)) %>% top_n(n = 1)
Selecting by Total
crime_by_psa <- as.data.frame(crime_by_psa)
crime_by_psa$psa <- factor(crime_by_psa$psa)
crime_by_psa$text_general_code <- factor(crime_by_psa$text_general_code)

head(crime_by_psa)
ggplot(crime_by_psa, aes(psa, Total, fill = text_general_code)) + 
  geom_bar(stat = "identity") + 
  ggtitle("Top crime in Every Police Service Area") + 
  xlab("Police Service Area") + 
  ylab("Total")



crime_by_dc_psa <- crime  %>% 
group_by(dc_dist, psa, text_general_code) %>% 
  dplyr::summarise(Total = n()) %>% 
  arrange(desc(Total)) %>% top_n(n = 1)
Selecting by Total
crime_by_dc_psa <- as.data.frame(crime_by_dc_psa)
crime_by_dc_psa$dc_dist <- factor(crime_by_dc_psa$dc_dist)
crime_by_dc_psa$text_general_code <- factor(crime_by_dc_psa$text_general_code)

ggplot(crime_by_dc_psa, aes(dc_dist, psa, fill = text_general_code)) + 
  geom_tile(color = "white") + 
  ggtitle("Top crime in Every Police Service Area and District Head Quarters") + 
  xlab("District Police HeadQuarters") + 
  ylab("Police Service Area")

Predictive Model - ARIMA Model

Several explorations have pointed out that crime seems to be seasonal and we wanted to explore this with a time series. Assuming that seasonal trends might repeat themselves, we are exploring this using the forecast package and using linear regression to predict trends.

Crimes by month

We can clearly see a downward trend in overall crime rates and also the fact that there seem to be seasonal peaks and declines.

bymo <- crime_data[order(Month_Year), .N, by=Month_Year]
dts <- ts(bymo$N, start = c(2006,1), frequency = 12)
dts_decomp<-decompose(dts, "multiplicative")
plot(dts,ylab="Total Crimes", main = "Monthly crimes with trend")
lines(dts_decomp$time.series[,2], col="tomato")

Seasonal component extracted from the timeseries.

plot(dts_decomp)

How seasonal is the data?

This autocorrelation shows a very high correlation every 12 months.

Acf(dts, main = "ACF of crime")

Forecast with a linear model

The red line shows the model’s prediction against the actual numbers in black. The model seems quite close.

f_crime <- tslm(dts ~ trend + season)
ff_crime <- forecast(f_crime,level=c(99),h =12)
plot(ff_crime)
lines(fitted(ff_crime), col = "red")

Residuals from model

This shows the residuals

res <- residuals(ff_crime)
plot(res, ylab="Residuals",xlab="Year", main = "Residuals") 

summary(res)
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
-6396.44  -456.31   -24.36     0.00   529.46  1800.72 

Predictions

Here are the predicted overall crime numbers.

Conclusion:

LS0tCnRpdGxlOiAiQ3JpbWUgRGF0YSBBbmFseXNpcyBhbmQgUHJlZGljdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIEFib3V0IFBoaWxhZGVscGhpYQoKUGhpbGFkZWxwaGlhLCBQZW5uc3lsdmFuaWHigJlzIGxhcmdlc3QgY2l0eSwgaXMgbm90YWJsZSBmb3IgaXRzIHJpY2ggaGlzdG9yeSwgb24gZGlzcGxheSBhdCB0aGUgTGliZXJ0eSBCZWxsLCBJbmRlcGVuZGVuY2UgSGFsbCAod2hlcmUgdGhlIERlY2xhcmF0aW9uIG9mIEluZGVwZW5kZW5jZSBhbmQgQ29uc3RpdHV0aW9uIHdlcmUgc2lnbmVkKSBhbmQgb3RoZXIgQW1lcmljYW4gUmV2b2x1dGlvbmFyeSBzaXRlcy4gQWxzbyBpY29uaWMgYXJlIHRoZSBzdGVwcyBvZiB0aGUgUGhpbGFkZWxwaGlhIE11c2V1bSBvZiBBcnQsIGltbW9ydGFsaXplZCBieSBTeWx2ZXN0ZXIgU3RhbGxvbmXigJlzIHRyaXVtcGhhbnQgcnVuIGluIHRoZSBmaWxtIOKAnFJvY2t5LuKAnQoKRGF0YSB3YXMgcHJvdmlkZWQgYnkgaHR0cHM6Ly93d3cub3BlbmRhdGFwaGlsbHkub3JnLwoKIyMjIENyaW1lIEluY2lkZW50cwoKQ3JpbWUgaW5jaWRlbnRzIGZyb20gdGhlIFBoaWxhZGVscGhpYSBQb2xpY2UgRGVwYXJ0bWVudC4gUGFydCBJIGNyaW1lcyBpbmNsdWRlIHZpb2xlbnQgb2ZmZW5zZXMgc3VjaCBhcyBhZ2dyYXZhdGVkIGFzc2F1bHQsIHJhcGUsIGFyc29uLCBhbW9uZyBvdGhlcnMuIFBhcnQgSUkgY3JpbWVzIGluY2x1ZGUgc2ltcGxlIGFzc2F1bHQsIHByb3N0aXR1dGlvbiwgZ2FtYmxpbmcsIGZyYXVkLCBhbmQgb3RoZXIgbm9uLXZpb2xlbnQgb2ZmZW5zZXMuCgpUaGlzIGRhdGFzZXQgcHJldmlvdXNseSBoYWQgc2VwYXJhdGUgZW5kcG9pbnRzIGZvciB2YXJpb3VzIHllYXJzIGFuZCB0eXBlcyBvZiBpbmNpZGVudHMuIFRoZXNlIGhhdmUgc2luY2UgYmVlbiBjb25zb2xpZGF0ZWQgaW50byBhIHNpbmdsZSBkYXRhc2V0LgoKIyMjIyBMb2FkaW5nIGFuZCB0YWtpbmcgYSBsb29rIGludG8gdGhlIGRhdGFzZXQKCmBgYHtyfQojaW5zdGFsbC5wYWNrYWdlcygibHVicmlkYXRlIikKI2luc3RhbGwucGFja2FnZXMoInZpcmlkIikKI2luc3RhbGwucGFja2FnZXMoInBsb3RseSIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ0bSIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ3b3JkY2xvdWQiKQojaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldCIpCiNpbnN0YWxsLnBhY2thZ2VzKCJ4dHMiKQojaW5zdGFsbC5wYWNrYWdlcygiaGlnaGNoYXJ0ZXIiKQojaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodHNlcmllcykKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeSh0aWR5cikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh0bSkKbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoeHRzKQpsaWJyYXJ5KGhpZ2hjaGFydGVyKQpgYGAKCiMjIyMgRGF0YSBzaXplIGFuZCBzdHJ1Y3R1cmUuCgpgYGB7cn0KY3JpbWVfZGF0YSA8LSBmcmVhZCgicGhpbGx5X2NyaW1lLmNzdiIsIHNob3dQcm9ncmVzcyA9IEZBTFNFKQpkaW0oY3JpbWVfZGF0YSkKc3RyKGNyaW1lX2RhdGEpCmBgYAoKYGBge3J9CnRhYmxlKGlzLm5hKGNyaW1lX2RhdGEpKQpgYGAKKiBPdmVyIDQ3ayByZWNvcmRzIGhhdmUgbWlzc2luZyB2YWx1ZXMuCiogRGVsZXRpbmcgcmVjb3JkcyBoYXZpbmcgbWlzc2luZyB2YWx1ZXMuCgpgYGB7cn0KY3JpbWVfZGF0YTwtbmEub21pdChjcmltZV9kYXRhKQp0YWJsZShpcy5uYShjcmltZV9kYXRhKSkKYGBgCiogTm8gbWlzc2luZyB2YWx1ZXMgbm93CgojIyMjIEV4dHJhY3QgTW9udGggYW5kIFllYXIgZnJvbSB0aGUgZGlzcGF0Y2hfZGF0ZV90aW1lIGF0dHJpYnV0ZQoKYGBge3J9CmNyaW1lX2RhdGEkTW9udGhfWWVhciA8LSBmb3JtYXQoYXMuUE9TSVhjdChzdHJwdGltZShjcmltZV9kYXRhJGRpc3BhdGNoX2RhdGVfdGltZSwiJVktJW0tJWQgJUg6JU06JVMiLHR6PSJHTVQiKSkgLGZvcm1hdCA9ICIlWS0lbSIpCmNyaW1lIDwtIGFzLmRhdGEuZnJhbWUoY3JpbWVfZGF0YSkKY3JpbWUkRGF5IDwtIGRheShjcmltZSRkaXNwYXRjaF9kYXRlX3RpbWUpCmNyaW1lJFllYXIgPC0gZmFjdG9yKHllYXIoY3JpbWUkZGlzcGF0Y2hfZGF0ZV90aW1lKSwgbGV2ZWxzPTIwMDY6MjAxOSkKY3JpbWUkTW9udGggPC0gZmFjdG9yKG1vbnRoKGNyaW1lJGRpc3BhdGNoX2RhdGVfdGltZSksIGxldmVscz0xOjEyKQpjcmltZSRkaXNwYXRjaF9kYXRlIDwtIGFzLkRhdGUoY3JpbWUkZGlzcGF0Y2hfZGF0ZSkKYGBgCgojIyMjIFRpbWUgU2VyaWVzIHBsb3Qgb2YgUGhpbGFkZWxwaGlhIENyaW1lcwoKU2luY2UgdGhlIGRhdGEgaXMgaW4gYSBzZXJpZXMgb2YgcGFydGljdWxhciB0aW1lIHBlcmlvZHMgb3IgaW50ZXJ2YWxzLCB3ZSBhcmUgcGxvdHRpbmcgdGltZSBzZXJpZXMgdG8gbG9vayBhdCB0cmVuZHMgb3ZlciB5ZWFycwpgYGB7cn0KYnlfZGF0ZSA8LSBjcmltZSAlPiUgZ3JvdXBfYnkoZGlzcGF0Y2hfZGF0ZSkgJT4lIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkKdHNlcmllcyA8LSB4dHMoYnlfZGF0ZSRUb3RhbCwgb3JkZXIuYnk9YXMuUE9TSVhjdChieV9kYXRlJGRpc3BhdGNoX2RhdGUpKQpoY2hhcnQodHNlcmllcywgbmFtZSA9ICJDcmltZXMiKSAlPiUgCiAgaGNfYWRkX3RoZW1lKGhjX3RoZW1lX2Rhcmt1bmljYSgpKSAlPiUKICBoY19jcmVkaXRzKGVuYWJsZWQgPSBUUlVFLCB0ZXh0ID0gIkRhdGEgU291cmNlOiBodHRwczovL3d3dy5vcGVuZGF0YXBoaWxseS5vcmcvICIsIHN0eWxlID0gbGlzdChmb250U2l6ZSA9ICIxMnB4IikpICU+JQogIGhjX3RpdGxlKHRleHQgPSAiVGltZSBTZXJpZXMgcGxvdCBvZiBQaGlsYWRlbHBoaWEgQ3JpbWVzIikgJT4lCiAgaGNfbGVnZW5kKGVuYWJsZWQgPSBUUlVFKQpgYGAKIyMjIyBMb2NhdGlvbiB3aXRoIE1vc3QgQ3JpbWVzIC0gVG9wIDIwCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9OSwgZmlnLmhlaWdodD01LjV9CmJ5X2xvY2F0aW9uIDwtIGNyaW1lICU+JSBncm91cF9ieShsb2NhdGlvbl9ibG9jaykgJT4lIAogIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhUb3RhbCkpCmhjaGFydChieV9sb2NhdGlvblsxOjIwLF0sICJjb2x1bW4iLCBoY2Flcyh4ID0gbG9jYXRpb25fYmxvY2ssIHkgPSBUb3RhbCwgY29sb3IgPSBUb3RhbCkpICU+JQogIGhjX2NvbG9yQXhpcyhzdG9wcyA9IGNvbG9yX3N0b3BzKG4gPSAxMCwgY29sb3JzID0gYygiIzQ0MDMyMSIsICIjMjE5MDhDIiwgIiNGREU3MjUiKSkpICU+JQogIGhjX2FkZF90aGVtZShoY190aGVtZV9kYXJrdW5pY2EoKSkgJT4lCiAgaGNfdGl0bGUodGV4dCA9ICJMb2NhdGlvbnMgd2l0aCBtb3N0IENyaW1lcyAtIFRvcCAyMCIpICU+JQogIGhjX2NyZWRpdHMoZW5hYmxlZCA9IFRSVUUsIHRleHQgPSAiRGF0YSBTb3VyY2U6IGh0dHBzOi8vd3d3Lm9wZW5kYXRhcGhpbGx5Lm9yZy8iLCBzdHlsZSA9IGxpc3QoZm9udFNpemUgPSAiMTVweCIpKSAlPiUKICBoY19sZWdlbmQoZW5hYmxlZCA9IEZBTFNFKQpgYGAKV2UgY2FuIG9ic2VydmUgdGhhdCA1MjAwIEJMT0NLIEZyYW5rZm9yZCBBdmUgaGFzIGhpZ2hlc3QgbnVtYmVyIG9mIGNyaW1lcyByZWNvcmRlZC4KCiMjIyMgTW9udGggY29tcGFyaXNvbiBmb3IgZWFjaCB5ZWFyKDIwMDYgLSAyMDE5KQpgYGB7ciB3YXJuaW5nPUZBTFNFLGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTUuNX0KbW9udGhwbG90IDwtIGdncGxvdChjcmltZSwgYWVzKFllYXIpKSArIAogICAgZ2VvbV9iYXIoZmlsbD0iI0ZGODY4NSIpICsKICAgIGdndGl0bGUoIk1vbnRoIGNvbXBhcmlzb24gZm9yIGVhY2ggeWVhcigyMDA2IC0gMjAxOSkiKSArCiAgICBmYWNldF93cmFwKH5Nb250aCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9MTIwKSkKZ2cyIDwtIGdncGxvdGx5KG1vbnRocGxvdCkKZ2cyCmBgYAojIyMgQ3JpbWVzIGJ5IEhvdXIsIERheSwgTW9udGggYW5kIFllYXIKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmJ5X2hvdXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KGhvdXJfKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKYnlfaG91cgpnZ3Bsb3QoYnlfaG91ciwgYWVzKGhvdXJfLCBUb3RhbCwgY29sb3IgPSBob3VyXykpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgSG91ciIpICsgCiAgeGxhYigiSG91ciBvZiB0aGUgRGF5IikgKyAKICB5bGFiKCJUb3RhbCBDcmltZXMiKSAKCmJ5X2RheSA8LSBjcmltZSAlPiUgCiAgZ3JvdXBfYnkoRGF5KSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKYnlfZGF5CgpnZ3Bsb3QoYnlfZGF5LCBhZXMoRGF5LCBUb3RhbCwgY29sb3IgPSBEYXkpKSArIAogIGdlb21fbGluZSgpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IERheSIpICsgCiAgeGxhYigiRGF5IG9mIHRoZSBNb250aCIpICsgCiAgeWxhYigiVG90YWwgQ3JpbWVzIikgCgpieV9tb250aCA8LSBjcmltZSAlPiUgCiAgZ3JvdXBfYnkoTW9udGgpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKQoKYnlfbW9udGgkUGVyY2VudCA8LSBieV9tb250aCRUb3RhbC9kaW0oY3JpbWUpWzFdICogMTAwCmJ5X21vbnRoCgpnZ3Bsb3QoYnlfbW9udGgsIGFlcyhNb250aCwgVG90YWwsIGZpbGwgPSBNb250aCkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IE1vbnRoIikgKyAKICB4bGFiKCJNb250aCIpICsgCiAgeWxhYigiQ291bnQiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmJ5X3llYXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKQpieV95ZWFyJFBlcmNlbnQgPC0gYnlfeWVhciRUb3RhbC9kaW0oY3JpbWUpWzFdICogMTAwCmJ5X3llYXIKCmdncGxvdChieV95ZWFyLCBhZXMoWWVhciwgVG90YWwsIGZpbGwgPSBZZWFyKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIkNyaW1lcyBCeSBZZWFyICIpICsgCiAgeGxhYigiWWVhciIpICsgeWxhYigiQ291bnQiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpieV9ob3VyX3llYXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KFllYXIsaG91cl8pICU+JQogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpCgpnZ3Bsb3QoYnlfaG91cl95ZWFyLCBhZXMoaG91cl8sIFRvdGFsLCBjb2xvciA9IFllYXIpKSArIAogIGdlb21fbGluZShzaXplID0gMSkgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgWWVhciBhbmQgSG91ciIpICsgCiAgeGxhYigiSG91ciBvZiB0aGUgRGF5IikgKyAKICB5bGFiKCJUb3RhbCBDcmltZXMiKSAKCmJ5X2hvdXJfbW9udGggPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KE1vbnRoLGhvdXJfKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9ob3VyX21vbnRoLCBhZXMoaG91cl8sIFRvdGFsLCBjb2xvciA9IE1vbnRoKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDEpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IE1vbnRoIGFuZCBIb3VyIikgKyAKICB4bGFiKCJIb3VyIG9mIHRoZSBEYXkiKSArIAogIHlsYWIoIlRvdGFsIENyaW1lcyIpIAoKYnlfbW9udGhfZGF5IDwtIGNyaW1lICU+JSAKICBncm91cF9ieShNb250aCwgRGF5KSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9tb250aF9kYXksIGFlcyhEYXksIFRvdGFsLCBjb2xvciA9IE1vbnRoKSkgKyAKICBnZW9tX2xpbmUoc2l6ZSA9IDIpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IE1vbnRoIGFuZCBEYXkiKSArIAogIHhsYWIoIkRheSIpICsgCiAgeWxhYigiQ291bnQiKQoKCmJ5X21vbnRoX3llYXIgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KFllYXIsIE1vbnRoKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9tb250aF95ZWFyLCBhZXMoWWVhciwgTW9udGgsIGZpbGwgPSBUb3RhbCkpICsgCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgWWVhciBhbmQgTW9udGgiKSArIAogIHhsYWIoIlllYXIiKSArIAogIHlsYWIoIk1vbnRoIikgCmBgYAojIyMgQ3JpbWVzIGJ5IENvZGUsIE1vbnRoIGFuZCBZZWFyCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmJ5X2NvZGUgPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KHRleHRfZ2VuZXJhbF9jb2RlKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhUb3RhbCkpCgpieV9jb2RlWzE6NTAsXQoKZ2dwbG90KGJ5X2NvZGUsIGFlcyhyZW9yZGVyKHRleHRfZ2VuZXJhbF9jb2RlLCBUb3RhbCksIFRvdGFsKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkgKyAgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDQ1MDAwMCw1MDAwMCkpICsgCiAgZ2d0aXRsZSgiQ3JpbWVzIEJ5IENvZGUiKSArIAogIHhsYWIoIkNyaW1lIFRleHQgQ29kZSIpICsgCiAgeWxhYigiVG90YWwgQ3JpbWVzIikKCmJ5X2NvZGVfeWVhciA8LSBjcmltZSAlPiUgZ3JvdXBfYnkoWWVhciwgdGV4dF9nZW5lcmFsX2NvZGUpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKQoKYnlfY29kZV95ZWFyWzE6MTAsXQoKZ2dwbG90KGJ5X2NvZGVfeWVhciwgYWVzKHJlb3JkZXIodGV4dF9nZW5lcmFsX2NvZGUsIFRvdGFsKSwgVG90YWwsIGZpbGwgPSBZZWFyKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNDUwMDAwLDUwMDAwKSkgKyAKICBjb29yZF9mbGlwKCkgKyBnZ3RpdGxlKCJDcmltZXMgQnkgQ29kZSBhbmQgWWVhciIpICsgCiAgeGxhYigiQ3JpbWUgVGV4dCBDb2RlIikgKyAKICB5bGFiKCJUb3RhbCBDcmltZXMiKQoKCmJ5X2NvZGVfbW9udGggPC0gY3JpbWUgJT4lIAogIGdyb3VwX2J5KE1vbnRoLCB0ZXh0X2dlbmVyYWxfY29kZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpCmJ5X2NvZGVfbW9udGhbMToxMCxdCmdncGxvdChieV9jb2RlX21vbnRoLCBhZXMocmVvcmRlcih0ZXh0X2dlbmVyYWxfY29kZSwgVG90YWwpLCBUb3RhbCwgZmlsbCA9IE1vbnRoKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsNDUwMDAwLDUwMDAwKSkgKyAKICBjb29yZF9mbGlwKCkgKyAKICBnZ3RpdGxlKCJDcmltZXMgQnkgQ29kZSBhbmQgTW9udGgiKSArIAogIHhsYWIoIkNyaW1lIFRleHQgQ29kZSIpICsgCiAgeWxhYigiVG90YWwgQ3JpbWVzIikKYGBgCiMjIyBDcmltZSBUeXBlcwoKYGBge3Igd2FybmluZz1GQUxTRX0KYnlfdHlwZSA8LSBjcmltZSAlPiUgZ3JvdXBfYnkodGV4dF9nZW5lcmFsX2NvZGUpICU+JSAKICBzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MoVG90YWwpKQpoY2hhcnQoYnlfdHlwZSwgImNvbHVtbiIsIGhjYWVzKHRleHRfZ2VuZXJhbF9jb2RlLCB5ID0gVG90YWwsIGNvbG9yID0gVG90YWwpKSAlPiUKICBoY19jb2xvckF4aXMoc3RvcHMgPSBjb2xvcl9zdG9wcyhuID0gMTAsIGNvbG9ycyA9IGMoIiM0NDAxNTQiLCAiIzIxOTA4QyIsICIjRkRFNzI1IikpKSAlPiUKICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZGFya3VuaWNhKCkpICU+JQogIGhjX3RpdGxlKHRleHQgPSAiQ3JpbWUgVHlwZXMiKSAlPiUKICBoY19jcmVkaXRzKGVuYWJsZWQgPSBUUlVFLCB0ZXh0ID0gIlNvdXJjZXM6IFBoaWxhZGVscGhpYSBQb2xpY2UgRGVwYXJ0bWVudCIsIHN0eWxlID0gbGlzdChmb250U2l6ZSA9ICIxMnB4IikpICU+JQogIGhjX2xlZ2VuZChlbmFibGVkID0gRkFMU0UpCmBgYAojIyMgU29tZSBUb3AgQ3JpbWVzIAoKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lICA8LSBmdW5jdGlvbih2YXJjcmltZSkgewogIGNyaW1lcyA8LSBjcmltZVtjcmltZSR0ZXh0X2dlbmVyYWxfY29kZSA9PSB2YXJjcmltZSxdIAogIGNyaW1lc19ieV9kYXRlIDwtIGNyaW1lcyAlPiUgZ3JvdXBfYnkoZGlzcGF0Y2hfZGF0ZSkgJT4lIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpCiAgY3JpbWVzX2J5X2RhdGUkZGlzcGF0Y2hfZGF0ZSA8LSBhcy5EYXRlKGNyaW1lc19ieV9kYXRlJGRpc3BhdGNoX2RhdGUpCiAgdHNlcmllcyA8LSB4dHMoY3JpbWVzX2J5X2RhdGUkVG90YWwsIG9yZGVyLmJ5PWFzLlBPU0lYY3QoY3JpbWVzX2J5X2RhdGUkZGlzcGF0Y2hfZGF0ZSkpCiAgaGNoYXJ0KHRzZXJpZXMsIG5hbWUgPSAiQ3JpbWVzIikgJT4lIAogICAgaGNfY29sb3JBeGlzKHN0b3BzID0gY29sb3Jfc3RvcHMobiA9IDEwLCBjb2xvcnMgPSBjKCIjNDQwMTU0IiwgIiMyMTkwOEMiLCAiI0ZERTcyNSIpKSkgJT4lCiAgICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfZGFya3VuaWNhKCkpICU+JQogICAgaGNfdGl0bGUodGV4dCA9IHZhcmNyaW1lKSAlPiUKICAgIGhjX2NyZWRpdHMoZW5hYmxlZCA9IFRSVUUsIHRleHQgPSAiU291cmNlczogUGhpbGFkZWxwaGlhIFBvbGljZSBEZXBhcnRtZW50Iiwgc3R5bGUgPSBsaXN0KGZvbnRTaXplID0gIjEycHgiKSkgJT4lCiAgICBoY19sZWdlbmQoZW5hYmxlZCA9IEZBTFNFKQp9CmBgYAoKYGBge3Igd2FybmluZz1GQUxTRSB9CnBsb3RjcmltZSgiQWxsIE90aGVyIE9mZmVuc2VzIikKYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpwbG90Y3JpbWUoIk90aGVyIEFzc2F1bHRzIikKYGBgCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnBsb3RjcmltZSgiVGhlZnRzIikKYGBgCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnBsb3RjcmltZSgiRnJhdWQiKQpgYGAKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lKCJUaGVmdCBmcm9tIFZlaGljbGUiKQpgYGAKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lKCJWYW5kYWxpc20vQ3JpbWluYWwgTWlzY2hpZWYiKQpgYGAKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdGNyaW1lKCJOYXJjb3RpYyAvIERydWcgTGF3IFZpb2xhdGlvbnMiKQpgYGAKIyMjIENyaW1lcyBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIGFuZCBQb2xpY2UgU2VydmljZSBBcmVhCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnRhYmxlKGNyaW1lJGRjX2Rpc3QpCnRhYmxlKGNyaW1lJHBzYSkKCmNyaW1lJGRjX2Rpc3QgPC0gZmFjdG9yKGNyaW1lJGRjX2Rpc3QpCgpieV9kYyA8LSBjcmltZSAlPiUgZ3JvdXBfYnkoZGNfZGlzdCkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSAKICBkcGx5cjo6YXJyYW5nZShkZXNjKFRvdGFsKSkKCmJ5X2RjX3BzYSA8LSBjcmltZSAlPiUgCiAgZ3JvdXBfYnkoZGNfZGlzdCwgcHNhKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkKCmdncGxvdChieV9kYywgYWVzKHJlb3JkZXIoZGNfZGlzdCwgLVRvdGFsKSwgVG90YWwpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdndGl0bGUoIkNyaW1lcyBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB4bGFiKCJQb2xpY2UgSFEiKSArIAogIHlsYWIoIlRvdGFsIENyaW1lcyIpIApieV9kY190b3A1IDwtIGJ5X2RjJGRjX2Rpc3RbMTo1XQpieV90b3A1X2RjIDwtIHN1YnNldChjcmltZSwgZGNfZGlzdCAlaW4lIGJ5X2RjJGRjX2Rpc3RbMTo1XSkKYnlfdG9wNV9kYyRkY19kaXN0IDwtIGZhY3RvcihieV90b3A1X2RjJGRjX2Rpc3QpCgpnZ3Bsb3QoYnlfdG9wNV9kYywgYWVzKGRjX2Rpc3QsIGZpbGwgPSBwc2EpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKyAKICBnZ3RpdGxlKCJDcmltZXMgYnkgRGlzdHJpY3QgUG9saWNlIEhlYWRRdWFydGVycyAtIFRvcCA1IikgKyAKICB4bGFiKCJQb2xpY2UgSFEiKSArIAogIHlsYWIoIlRvdGFsIENyaW1lcyIpIAoKZ2dwbG90KGJ5X2RjX3BzYSwgYWVzKGRjX2Rpc3QsIHBzYSwgZmlsbCA9IFRvdGFsKSkgKyAKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArIAogIGdndGl0bGUoIkNyaW1lcyBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIGFuZCBQb2xpY2UgU2VydmljZSBBcmVhIikgKyAKICB4bGFiKCJEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB5bGFiKCJQb2xpY2UgU2VydmljZSBBcmVhIikgCmBgYAojIyMgVG9wIGNyaW1lIGluIGV2ZXJ5IERpc3RyaWN0IEhlYWQgUXVhcnRlcnMgIGFuZCBldmVyeSBQb2xpY2UgU2VydmljZSBBcmVhCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpkY19ieV9jcmltZSA8LSBjcmltZSAgJT4lIAogIGdyb3VwX2J5KGRjX2Rpc3QsIHRleHRfZ2VuZXJhbF9jb2RlKSAlPiUgCiAgZHBseXI6OnN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhUb3RhbCkpICU+JSB0b3BfbihuID0gMSkKCmRjX2J5X2NyaW1lIDwtIGFzLmRhdGEuZnJhbWUoZGNfYnlfY3JpbWUpCmRjX2J5X2NyaW1lJGRjX2Rpc3QgPC0gZmFjdG9yKGRjX2J5X2NyaW1lJGRjX2Rpc3QpCmRjX2J5X2NyaW1lJHRleHRfZ2VuZXJhbF9jb2RlIDwtIGZhY3RvcihkY19ieV9jcmltZSR0ZXh0X2dlbmVyYWxfY29kZSkKCmdncGxvdChkY19ieV9jcmltZSwgYWVzKGRjX2Rpc3QsIFRvdGFsLCBmaWxsID0gdGV4dF9nZW5lcmFsX2NvZGUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdndGl0bGUoIlRvcCBDcmltZSBieSBEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB4bGFiKCJEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB5bGFiKCJUb3RhbCIpIAoKY3JpbWVfYnlfcHNhIDwtIGNyaW1lICAlPiUgCiAgZ3JvdXBfYnkocHNhLCB0ZXh0X2dlbmVyYWxfY29kZSkgJT4lIAogIGRwbHlyOjpzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSAKICBhcnJhbmdlKGRlc2MoVG90YWwpKSAlPiUgdG9wX24obiA9IDEpCgpjcmltZV9ieV9wc2EgPC0gYXMuZGF0YS5mcmFtZShjcmltZV9ieV9wc2EpCmNyaW1lX2J5X3BzYSRwc2EgPC0gZmFjdG9yKGNyaW1lX2J5X3BzYSRwc2EpCmNyaW1lX2J5X3BzYSR0ZXh0X2dlbmVyYWxfY29kZSA8LSBmYWN0b3IoY3JpbWVfYnlfcHNhJHRleHRfZ2VuZXJhbF9jb2RlKQoKaGVhZChjcmltZV9ieV9wc2EpCmdncGxvdChjcmltZV9ieV9wc2EsIGFlcyhwc2EsIFRvdGFsLCBmaWxsID0gdGV4dF9nZW5lcmFsX2NvZGUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIAogIGdndGl0bGUoIlRvcCBjcmltZSBpbiBFdmVyeSBQb2xpY2UgU2VydmljZSBBcmVhIikgKyAKICB4bGFiKCJQb2xpY2UgU2VydmljZSBBcmVhIikgKyAKICB5bGFiKCJUb3RhbCIpCgoKY3JpbWVfYnlfZGNfcHNhIDwtIGNyaW1lICAlPiUgCmdyb3VwX2J5KGRjX2Rpc3QsIHBzYSwgdGV4dF9nZW5lcmFsX2NvZGUpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKFRvdGFsID0gbigpKSAlPiUgCiAgYXJyYW5nZShkZXNjKFRvdGFsKSkgJT4lIHRvcF9uKG4gPSAxKQoKY3JpbWVfYnlfZGNfcHNhIDwtIGFzLmRhdGEuZnJhbWUoY3JpbWVfYnlfZGNfcHNhKQpjcmltZV9ieV9kY19wc2EkZGNfZGlzdCA8LSBmYWN0b3IoY3JpbWVfYnlfZGNfcHNhJGRjX2Rpc3QpCmNyaW1lX2J5X2RjX3BzYSR0ZXh0X2dlbmVyYWxfY29kZSA8LSBmYWN0b3IoY3JpbWVfYnlfZGNfcHNhJHRleHRfZ2VuZXJhbF9jb2RlKQoKZ2dwbG90KGNyaW1lX2J5X2RjX3BzYSwgYWVzKGRjX2Rpc3QsIHBzYSwgZmlsbCA9IHRleHRfZ2VuZXJhbF9jb2RlKSkgKyAKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArIAogIGdndGl0bGUoIlRvcCBjcmltZSBpbiBFdmVyeSBQb2xpY2UgU2VydmljZSBBcmVhIGFuZCBEaXN0cmljdCBIZWFkIFF1YXJ0ZXJzIikgKyAKICB4bGFiKCJEaXN0cmljdCBQb2xpY2UgSGVhZFF1YXJ0ZXJzIikgKyAKICB5bGFiKCJQb2xpY2UgU2VydmljZSBBcmVhIikKYGBgCiogQWxsIG90aGVyIE9mZmVuc2VzIGNsYXNzaWZpY2F0aW9uIGlzIG1vc3QgY29tbW9uIGFtb25nIGFsbCB0aGUgRGlzdHJpY3QgSGVhZFF1YXJ0ZXJzLCBTZWNvbmQgYmVpbmcgT3RoZXIgQXNzYXVsdHMKKiBJdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBzZWUgaG93IHRoZXNlIHR3byBoYXZlIGluY3JlYXNlZCBvciBkZWNyZWFzZWQgb3ZlciB0aGUgeWVhcnMKKiBBbGwgb3RoZXIgT2ZmZW5zZXMgY2xhc3NpZmljYXRpb24gaXMgbW9zdCBjb21tb24gYW1vbmcgYWxsIFBvbGljZSBTZXJ2aWNlIEFyZWFzCiogQXNzYXVsdHMgaXMgbW9zdCBjb21tb24gaW4gRGlzdHJpY3QgSFEgMTQKKiBWZXJ5IGludGVyZXN0aW5nIG9uZSBpcyBUaGVmdHMgZnJvbSBWZWhpY2xlIGFuZCBtb3RvciB2ZWhpY2xlIHJlY292ZXJ5IGFyZSB0aGUgb25seSBjcmltZXMgaW4gRGlzdHJpY3QgSFEgOTIuCiogQWxzbyB3ZSBjYW4gc2VlIHRoYXQgaW4gRGlzdHJpY3QgSFEgNzcgdGhlcmUgaXMgb25seSBvbmUgdHlwZSBvZiBjcmltZSByZXBvcnRlZCBpLmUuIFRoZWZ0cy4KCiMjIyBQcmVkaWN0aXZlIE1vZGVsIC0gQVJJTUEgTW9kZWwKClNldmVyYWwgZXhwbG9yYXRpb25zIGhhdmUgcG9pbnRlZCBvdXQgdGhhdCBjcmltZSBzZWVtcyB0byBiZSBzZWFzb25hbCBhbmQgd2Ugd2FudGVkIHRvIGV4cGxvcmUgdGhpcyB3aXRoIGEgdGltZSBzZXJpZXMuIEFzc3VtaW5nIHRoYXQgc2Vhc29uYWwgdHJlbmRzIG1pZ2h0IHJlcGVhdCB0aGVtc2VsdmVzLCB3ZSBhcmUgZXhwbG9yaW5nIHRoaXMgdXNpbmcgdGhlIGZvcmVjYXN0IHBhY2thZ2UgYW5kIHVzaW5nIGxpbmVhciByZWdyZXNzaW9uIHRvIHByZWRpY3QgdHJlbmRzLgoKIyMjIyBDcmltZXMgYnkgbW9udGgKV2UgY2FuIGNsZWFybHkgc2VlIGEgZG93bndhcmQgdHJlbmQgaW4gb3ZlcmFsbCBjcmltZSByYXRlcyBhbmQgYWxzbyB0aGUgZmFjdCB0aGF0IHRoZXJlIHNlZW0gdG8gYmUgc2Vhc29uYWwgcGVha3MgYW5kIGRlY2xpbmVzLgoKYGBge3J9CmJ5bW8gPC0gY3JpbWVfZGF0YVtvcmRlcihNb250aF9ZZWFyKSwgLk4sIGJ5PU1vbnRoX1llYXJdCmR0cyA8LSB0cyhieW1vJE4sIHN0YXJ0ID0gYygyMDA2LDEpLCBmcmVxdWVuY3kgPSAxMikKZHRzX2RlY29tcDwtZGVjb21wb3NlKGR0cywgIm11bHRpcGxpY2F0aXZlIikKcGxvdChkdHMseWxhYj0iVG90YWwgQ3JpbWVzIiwgbWFpbiA9ICJNb250aGx5IGNyaW1lcyB3aXRoIHRyZW5kIikKbGluZXMoZHRzX2RlY29tcCR0aW1lLnNlcmllc1ssMl0sIGNvbD0idG9tYXRvIikKYGBgCiMjIyMgU2Vhc29uYWwgY29tcG9uZW50IGV4dHJhY3RlZCBmcm9tIHRoZSB0aW1lc2VyaWVzLgpgYGB7cn0KcGxvdChkdHNfZGVjb21wKQpgYGAKIyMjIyBIb3cgc2Vhc29uYWwgaXMgdGhlIGRhdGE/ClRoaXMgYXV0b2NvcnJlbGF0aW9uIHNob3dzIGEgdmVyeSBoaWdoIGNvcnJlbGF0aW9uIGV2ZXJ5IDEyIG1vbnRocy4gCmBgYHtyfQpBY2YoZHRzLCBtYWluID0gIkFDRiBvZiBjcmltZSIpCmBgYAojIyMjIEZvcmVjYXN0IHdpdGggYSBsaW5lYXIgbW9kZWwKVGhlIHJlZCBsaW5lIHNob3dzIHRoZSBtb2RlbCdzIHByZWRpY3Rpb24gYWdhaW5zdCB0aGUgYWN0dWFsIG51bWJlcnMgaW4gYmxhY2suIFRoZSBtb2RlbCBzZWVtcyBxdWl0ZSBjbG9zZS4gCgpgYGB7cn0KZl9jcmltZSA8LSB0c2xtKGR0cyB+IHRyZW5kICsgc2Vhc29uKQpmZl9jcmltZSA8LSBmb3JlY2FzdChmX2NyaW1lLGxldmVsPWMoOTkpLGggPTEyKQpwbG90KGZmX2NyaW1lKQpsaW5lcyhmaXR0ZWQoZmZfY3JpbWUpLCBjb2wgPSAicmVkIikKYGBgCiMjIyMgUmVzaWR1YWxzIGZyb20gbW9kZWwKVGhpcyBzaG93cyB0aGUgcmVzaWR1YWxzCgpgYGB7cn0KcmVzIDwtIHJlc2lkdWFscyhmZl9jcmltZSkKcGxvdChyZXMsIHlsYWI9IlJlc2lkdWFscyIseGxhYj0iWWVhciIsIG1haW4gPSAiUmVzaWR1YWxzIikgCnN1bW1hcnkocmVzKQpgYGAKIyMjIyBQcmVkaWN0aW9ucwpIZXJlIGFyZSB0aGUgcHJlZGljdGVkIG92ZXJhbGwgY3JpbWUgbnVtYmVycy4gCgpgYGB7ciwgZWNobz1GQUxTRX0KZmZfY3JpbWUKYGBgCiMjIyBDb25jbHVzaW9uOgoKKiBUaGVyZSBpcyBkZWNyZWFzZSBpbiBvdmVyYWxsIGNyaW1lIGluIGxhc3QgMTUgeWVhcnMKKiBDcmltZXMgYXJlIG1vc3QgZHVyaW5nIG1pZGRsZSBxdWFydGVyIG9mIGV2ZXJ5IHllYXIoTWF5LUF1Z3VzdCkKKiBDcmltZXMgYXJlIGxlYXN0IGR1cmluZyBXaW50ZXIgc2Vhc29uIGFuZCBoaWdoZXN0IGR1cmluZyBTdW1tZXIgc2Vhc29uLgoqIENyaW1lcyBhcmUgbGVhc3QgYXJvdW5kIDZBTSBpbiB0aGUgbW9ybmluZwoqIENyaW1lcyBhcmUgbW9zdCBhcm91bmQgNFBNIGluIHRoZSBldmVuaW5nCiogVGhlcmUgaXMgY29tbW9uIHRyZW5kIGluIGNyaW1lcyBvdmVyIHRoZSB5ZWFycwoqIEFsbCBPdGhlciBPZmZlbnNlcywgT3RoZXIgQXNzdWx0cyBhbmQgVGhlZnRzIGFyZSB0aGUgdG9wIDMgQ3JpbWVzCiogVGhlZnRzIGhhdmUgaW5jcmVhc2VkIG92ZXIgdGhlIHllYXJzCiogTmFyY290aWMvRHJ1ZyBMYXcgVmlvbGF0aW9ucyBoYXZlIGRlY3JlYXNlZCBvdmVyIHRoZSB5ZWFycwoqIERpc3RyaWN0IFBvbGljZSBIZWFkIFF1YXJ0ZXJzIGNvZGVkIDE1LCAyNCBhbmQgMjUgaGF2ZSB0aGUgaGlnaGVzdCBudW1iZXIgb2YgY3JpbWVzIHJlcG9ydGVkLgoqIFRvcCBDcmltZSBpbiBldmVyeSBEaXN0cmljdCBQb2xpY2UgSGVhZCBRdWFydGVycyA6IEFsbCBvdGhlciBvZmZlbnNlcywgb3RoZXIgYXNzYXVsdHMsIHRoZWZ0cyBhbmQgdGhlZnQgZnJvbSB2ZWhpY2xlLgoK